/*
 * ManejadorArbol.cpp
 *
 *  Created on: 03/06/2010
 *      Author: Grupo Klow
 */

#include "ManejadorArbol.h"
#include <string.h>


	ManejadorArbol::ManejadorArbol(string nombre_archivo){

		//Supone nombre_archivo no vacio

		char* nombre_temp = ManejadorContexto::getNombreTemp(nombre_archivo);

		this->arbol = new ArbolB(nombre_temp, LONGITUD_BLOQUE);
		this->arbol->setModoTemporal(true);
		this->ultimoContextoProcesado = NULL;
		delete []nombre_temp;
	}

	Contexto* ManejadorArbol::buscarContexto(string contextoNombre){

		Nodo::TClave clave_devuelta;
		Nodo::TClave clave_aux = invertirNombreContexto(contextoNombre);
		Contexto* retorno=NULL;
		char * contextoData = NULL;
		//Evalua si es combiente buscar el contexto a partir de la raiz
		//o a través de una busqueda secuencial
		if (  this->ultimoContextoProcesado != NULL && (strlen(this->ultimoContextoProcesado) == strlen(clave_aux)+1) && strncmp(clave_aux,this->ultimoContextoProcesado, strlen(this->ultimoContextoProcesado)-1)==0) {
			//Combeine busqueda secuencial
			bool encontrado = false;
			bool claveMenorEncontrada = false;
			while (this->arbol->tieneAnterior() && !encontrado && !claveMenorEncontrada) {
				contextoData = (char*) this->arbol->getAnterior(&clave_devuelta);
				if ( strcmp(clave_devuelta,clave_aux)==0) {
					encontrado = true;
					retorno= new Contexto(contextoData, contextoNombre);
				} else if (strcmp(clave_devuelta,clave_aux)<0) {
					//Me pase. No esta la clave que se busca.
					claveMenorEncontrada = true;
				} else {
					free(clave_devuelta);
				}
				delete[](contextoData);
			}
		} else {
			contextoData = (char *)this->arbol->Buscar(clave_aux, &clave_devuelta);

			if(contextoData != NULL && strcmp(clave_devuelta,clave_aux)==0){
				retorno= new Contexto(contextoData, contextoNombre);
			}
			delete[](contextoData);
		}


		delete[]clave_aux;
		delete[](this->ultimoContextoProcesado);

		if (clave_devuelta!=NULL) {
			this->ultimoContextoProcesado = new char[strlen(clave_devuelta)+1];
			memcpy(this->ultimoContextoProcesado,clave_devuelta, strlen(clave_devuelta)+1);
		} else {
			this->ultimoContextoProcesado = NULL;
		}

		free(clave_devuelta);

		return retorno;
	}

	Nodo::TClave ManejadorArbol::invertirNombreContexto (string contextoNombre)
	{
		int longitud = contextoNombre.length();
		Nodo::TClave clave_invertida = new char[longitud + 1];
		Nodo::TClave clave_aux = new char[longitud + 1];

		strcpy(clave_aux, contextoNombre.c_str());

		int i;

		for (i = 0; i < longitud ; i++)
			memcpy(&clave_invertida[longitud-1-i], &clave_aux[i], sizeof (char));

		clave_invertida[longitud] = '\0';

		delete []clave_aux;
		return clave_invertida;
	}

	string ManejadorArbol::invertirClave (Nodo::TClave clave)
	{
		string nombreContexto = "";
		char * aux = new char [strlen(clave)+1];

		int i = strlen(clave);
		int j = 0;

		while (i > 0)
		{
			i--;
			aux[j] = clave[i];
			j++;
		}
		aux[j]='\0';
		nombreContexto.append(aux);

		delete[](aux);

		return nombreContexto;
	}

	ManejadorContexto::Resultado ManejadorArbol::altaContexto(Contexto* contexto){
		int tamanioData = 0;
		char * contextoData = contexto->contextoABytes(&tamanioData);
		Nodo::TClave clave_aux = invertirNombreContexto(contexto->getNombre());

		ArbolB::Resultado resultado = this->arbol->Insertar(clave_aux, contextoData, tamanioData);
		delete[](contextoData);
		if (resultado == this->arbol->OPERACION_EXITOSA) {
			delete[](this->ultimoContextoProcesado);
			this->ultimoContextoProcesado = clave_aux;
			return this->OPERACION_EXITOSA;
		} else {
			delete []clave_aux;
			return this->OPERACION_FALLIDA;
		}
	}

	ManejadorContexto::Resultado ManejadorArbol::modificarContexto(Contexto* contexto){
		int tamanioData = 0;
		char * contextoData = contexto->contextoABytes(&tamanioData);
		Nodo::TClave clave_aux = invertirNombreContexto(contexto->getNombre());

		ArbolB::Resultado resultado = this->arbol->Modificar(clave_aux, contextoData, tamanioData);
		delete[](contextoData);
		if (resultado == this->arbol->OPERACION_EXITOSA) {
			delete[](this->ultimoContextoProcesado);
			this->ultimoContextoProcesado = clave_aux;
			return this->OPERACION_EXITOSA;
		} else {
			delete []clave_aux;
			return this->OPERACION_FALLIDA;
		}
	}

	void ManejadorArbol::imprimirContextos(FILE * salida){
		Nodo::TClave clave_devuelta;
		char * ctxData = NULL;
		string nombreContexto;
		Contexto * ctx;


		this->arbol->iniciarRecorridoSecuencial();
		while (this->arbol->tieneSiguiente())
		{

			ctxData = (char *)this->arbol->getSiguiente(&clave_devuelta);
			nombreContexto = invertirClave(clave_devuelta);
			ctx = new Contexto(ctxData, nombreContexto);

			imprimirHelper(salida, ctx);

			delete(ctx);
			free(clave_devuelta);
			delete[](ctxData);
		}
	}

	ManejadorArbol::~ManejadorArbol(){
		delete[](this->ultimoContextoProcesado);
		if(arbol)
			delete this->arbol;
	}

